Objective: All HTTPS requests made directly to the server's IP address (e.g., https://1.2.3.4) should be permanently redirected (301) to a fixed, official hostname (e.g., https://srv1.yourdomain.com).
The Problem: Without a specific configuration, Nginx defaults to serving the first available SSL-enabled virtual host for such requests. This results in the certificate and website of an unrelated domain on the server being displayed.
When an HTTPS request is made to a hostname (e.g., yourdomain.com), the browser uses SNI (Server Name Indication) to tell the server which website it wants. Nginx can then select the correct server block and the corresponding SSL certificate.
However, when you access the server directly via its IP address (https://1.2.3.4), no hostname is sent via SNI. Nginx is uncertain and defaults to grabbing the first SSL server block it finds in its configuration.
The solution is to create an unambiguous "catch-all" server block that explicitly acts as the default for requests without a hostname.
/etc/nginx/conf.d/ directory. The 00_ prefix ensures that this file is loaded before any other configurations (like those from VestaCP), giving it priority.
sudo nano /etc/nginx/conf.d/00_default_https_redirect.conf
# /etc/nginx/conf.d/00_default_https_redirect.conf
server {
# Listen explicitly on the IP and mark this block as the
# default fallback for port 443.
listen YOUR-SERVER-IP:443 ssl default_server;
http2 on;
# A "catch-all" server_name. The underscore is the convention for this.
server_name _;
# IMPORTANT: Use the SSL certificate of the TARGET hostname
# to minimize handshake errors with clients.
ssl_certificate /home/admin/conf/web/ssl.YOUR-HOSTNAME.COM.pem;
ssl_certificate_key /home/admin/conf/web/ssl.YOUR-HOSTNAME.COM.key;
# Optional log files for debugging
access_log /var/log/nginx/ip_redirect.log;
error_log /var/log/nginx/ip_redirect.error.log;
# Perform the permanent 301 redirect to the official hostname.
# $request_uri preserves the original path and query parameters.
return 301 https://YOUR-HOSTNAME.COM$request_uri;
}
sudo nginx -t
The expected output is: syntax is ok and test is successful.
sudo systemctl reload nginx
The best way to test the redirect is from the command line using curl.
curl https://YOUR-SERVER-IP will fail with an SSL error! This is expected behavior because the certificate is issued for YOUR-HOSTNAME.COM, not for the IP address. We must bypass the certificate validation for this test using the -k flag.
Execute the following command:
curl -I -k https://YOUR-SERVER-IP
HTTP/2 301 response, which includes the location header pointing to your target hostname.
HTTP/2 301
server: nginx
date: ...
content-type: text/html
location: https://YOUR-HOSTNAME.COM/
...
In a web browser, visiting the IP address directly will show a security warning. If you click "Advanced" and proceed, the redirect will execute correctly, and you will land on your target domain.
This solution is "update-safe" as it will not be overwritten by VestaCP's configuration changes.